#include "Engine.h"
#include "Object.h"
#include "Draw.h"
#include "Timing.h"

#include "Game.h"

#include "GlutWindow.h"
#ifdef _WIN32
	#include "Win32Window.h"
#else
	#include "X11Window.h"
#endif

#include "IL/il.h"

#include <cstring>
#include <cstdlib>
#include <string>
#include <iostream>
#include <algorithm>

// --------------------------------------------------------------------
Engine Engine::engine;
// --------------------------------------------------------------------

// ---------------------------------------------------------------
Engine::Engine(void)
    : window(NULL), imageID(0), objetos(), materiais(),background()
{
}
// ---------------------------------------------------------------
Engine::~Engine(void)
{
	delete window;
	window = NULL;
    shutdown();
}
// ---------------------------------------------------------------
Engine& Engine::getInstance(void)
{
	return engine;
}
// ---------------------------------------------------------------
Object& Engine::getBackground(void)
{
	return background;
}
// ---------------------------------------------------------------
Material* Engine::addMaterial(void)
{
	Material* item = new Material();
	materiais.push_back( item );
	return item;
}
// ---------------------------------------------------------------
Material* Engine::addMaterial(const char* texture)
{
	Material* item = addMaterial();
	item->carregarTextura( texture );

	return item;
}
// ---------------------------------------------------------------
void Engine::clearUnusedMaterials(void)
{
	int i = (int) materiais.size() - 1;
	for(  ; i >= 0 ; --i )
	{
		Material* m = materiais[i];
		if( hasObjectUsing(m) )
			continue;

		materiais.erase( materiais.begin() + i );
		delete m;
	}

}
// ---------------------------------------------------------------
bool Engine::hasObjectUsing( Material* mat )
{
	if( background.getMaterial() == mat ) return true;

	for( unsigned int i=0; i< objetos.size() ; i++ )
	{
		if( objetos[i].getMaterial() == mat )
			return true;
	}

	return false;
}
// ---------------------------------------------------------------
Object& Engine::addObject(const String& name)
{
	Object* ptr = getObject( name );
	if( ptr ) return *ptr;

    Object obj;
    obj.name = name;
    objetos.push_back(obj);
    return objetos[objetos.size()-1];
}
Object* Engine::getObject(const String& name)
{
	for( unsigned int i=0; i<objetos.size() ; i++ )
		if( objetos[i].name == name )
		return &(objetos[i]);
	return NULL;
}
// ---------------------------------------------------------------
int Engine::loadTexture( const char* filename )
{
	int id = ilutGLLoadImage( (char*) filename);
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

	return id;
}
// ---------------------------------------------------------------
void Engine::startGame(void)
{
	Timing::getInstance().resume();
	if(window)
	{
		window->startRendering();
	}
}
// ---------------------------------------------------------------
bool Engine::init( const WindowSettings& settings )
{
	WindowSettings& params = const_cast<WindowSettings&>(settings);

	// TODO: cliente/servidor

	//window = new X11Window( settings );
	window = new GlutWindow( settings );

	// OpenIL
	ilutRenderer(ILUT_OPENGL);
	ilInit();
	iluInit();
	ilutInit();
	ilutRenderer(ILUT_OPENGL);

	ilGenImages( 1, &imageID );
	ilBindImage( imageID );

	//
	if( settings.hasParameter("--server") )
	{
		std::cout << "servidor\n";
		Game::getInstance().initServer( settings );
	}
	else
	if( settings.hasParameter("--nick") )
	{
		std::cout << "cliente!\n";
		Game::getInstance().initClient( settings );
	}
	else
	{
		return false;
	}

    return true;
}
// ---------------------------------------------------------------
void Engine::shutdown(void)
{
    ilDeleteImage( imageID );
     imageID = 0;

    // OpenIL
    ilShutDown();

    delete window;
    window = NULL;
}
// ---------------------------------------------------------------
WindowInterface* Engine::getWindow(void)
{
	return window;
}
// ---------------------------------------------------------------
void Engine::drawScene(void)
{
	static double delta = 0.0;
	//std::cout << Timing::getInstance().getSystemTime() << std::endl;
	Timing::getInstance().tick();


	if( window->isKeyDown( WindowInterface::KEYBOARD_UP ) )
		objetos[1].posicao.y += 0.33*delta;
	if( window->isKeyDown( WindowInterface::KEYBOARD_DOWN ) )
			objetos[1].posicao.y -= 0.33*delta;


    glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();

    // desenha o fundo do jogo
    glPushMatrix();
    	glLoadIdentity();
    	background.draw();
    glPopMatrix();

    for( unsigned int i=0; i<objetos.size() ; ++i )
    {
        glPushMatrix();
            glLoadIdentity();
            objetos[i].draw();
        glPopMatrix();
    }



    static Material opaco;
    opaco.cor.set(0.0f,0,0.0,0.9f);
    opaco.texturaHabilitada = false;
    opaco.usarMaterial();

//    Draw::drawQuad();

    static float angle = 45;

    angle += 0.6f;

    glFlush();
    window->swapBuffers();


    delta = Timing::getInstance().getElapsedTime();
    //std::cout << delta << std::endl;
}

